package cn.wolfcode.demo.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

/*
配置RedisTemplate
(缓存时间)
 */
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    //配置Redis作用默认的缓存工具
    @Bean
    public CacheManager cacheManger(RedisConnectionFactory redisConnectionFactory){
        //设定一下缓存的有效时间  单位 小时
        RedisCacheConfiguration redisCacheConfiguration=RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1));
        return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory)).cacheDefaults(redisCacheConfiguration).build();
    }
    //配置RedisTemplate相关的配置信息
    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
        //创建一个RedisTemplate对象，进行内部方法的自定义
        RedisTemplate<String,Object> template=new RedisTemplate();

        //配置连接工厂
        template.setConnectionFactory(factory);

        //指定要序列化的域（实体类中的属性和方法）
        Jackson2JsonRedisSerializer jacksonSeial=new Jackson2JsonRedisSerializer(Object.class);

        //指定可序列化的类型（private,public,get,set指定需要序列化的）,(JsonAuto...  按json格式序列化)
        ObjectMapper om=new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

        /*指定实体类中的输入类型，实体类中那些方法是可操作的，那些是不可操作的
         除final以外的属性或方法，都可以序列化，一旦遇到final就有异常提示
         */
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSeial.setObjectMapper(om);//使序列化实现

        //处理给页面返回的数据格式（json）
        template.setValueSerializer(jacksonSeial);
        template.setKeySerializer(new StringRedisSerializer());

        //设置 Hash key value 进行序列化模式的设定(使上面的数据格式生效)
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(jacksonSeial);
        template.afterPropertiesSet();

        //返回RedisTemplate对象，目的是让后续的service类调用其重写的方法进行操作
        return template;
    }
    //String类型
    @Bean
    public ValueOperations<String,Object> valueOperations(RedisTemplate<String,Object> redisTemplate){
        return redisTemplate.opsForValue();
    }

    //Hash类型
    @Bean
    public HashOperations<String,String,Object> hashOperations(RedisTemplate<String,Object> redisTemplate){
        return redisTemplate.opsForHash();
    }

    //list类型
    @Bean
    public ListOperations<String, Object> listOperations(RedisTemplate<String,Object> redisTemplate){
        return redisTemplate.opsForList();
    }

    //Set类型
    @Bean
    public SetOperations<String, Object> setOperations(RedisTemplate<String,Object> redisTemplate){
        return redisTemplate.opsForSet();
    }
    //zset
    @Bean
    public ZSetOperations<String, Object> zsetOperations(RedisTemplate<String,Object> redisTemplate){
        return redisTemplate.opsForZSet();
    }
}
